package com.issac.filter;

import cn.hutool.core.util.StrUtil;
import com.issac.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @ClassName JWTAuthenticationFilter
 * @Author zy
 * @Date 2021/11/17 14:56
 * @Description 二次认证验证token
 * @Version 1.0
 */
@Slf4j
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        // 从请求头中获取token
        String token = request.getHeader("Authorization");

        if (StrUtil.isBlankOrUndefined(token)) {
            chain.doFilter(request, response); // 会到达JwtAuthenticationEntryPoint
            return;
        }

        // 获取token中的声明
        Claims claim = JwtUtils.getClaimByToken(token);

        if (claim == null) {
            throw new JwtException("token异常！");
        }

        if (JwtUtils.isTokenExpired(claim)) {
            throw new JwtException("token已过期！");
        }

        //token是合法的

         /*
           获取到用户名之后直接封装成UsernamePasswordAuthenticationToken，
           之后交给SecurityContextHolder参数传递authentication对象，这样
           后续security就能获取到当前登录的用户信息了，也就完成了用户认证。
           个人理解为将用户信息存入springSecurity的上下文中
         */
        String accountId = claim.getSubject();
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                new UsernamePasswordAuthenticationToken(accountId, null,
                        AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);

//        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
//                new UsernamePasswordAuthenticationToken("accountId", null,
//                        AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));
//        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
//

        chain.doFilter(request, response);//放行
    }
}
